/**
 *
 *  @project Broadcast
 *  @author Toni Marquez
 *
 **/

/* INCLUDES */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>

/* STRUCT */

struct Data {
  char primitiva[25];
  char game[25];
  char ip[16];
  int port;
};

Data g_client_data, g_server_data;

/* VARS */

WSAData wsa;
SOCKET sock;
struct sockaddr_in ip_server, ip_client;

int g_ip_size;

/* METHODS */

// init WSA, sockets & connection with clients
void InitWSA(){
int flag_value = 1;

  WSAStartup(MAKEWORD(2, 0), &wsa);

  sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  ip_server.sin_family = AF_INET;
  ip_server.sin_addr.s_addr = inet_addr("0.0.0.0");
  ip_server.sin_port = htons(9999);

  g_ip_size = sizeof(ip_server);

  bind(sock, (SOCKADDR*)&ip_server, g_ip_size);

  setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&flag_value, sizeof(int));
}

// program engine
void Engine(){

  // fill struct
  memset(g_server_data.game, 0, 25);
  strncpy(g_server_data.game, "marquezll\0", 10);
  memset(g_server_data.ip, 0, 16);
  strcpy(g_server_data.ip, inet_ntoa(ip_server.sin_addr));
  g_server_data.port = 9999;

  while (true){

    // [1] receive GDP_DISCOVERY
    printf("waiting for clients...\n");
    memset(g_client_data.primitiva, 0, 25);
    recvfrom(sock, (char*)&g_client_data.primitiva, sizeof(g_client_data.primitiva), 0, (SOCKADDR*)&ip_client, &g_ip_size);
    printf("client request received\n");

    if (!strncmp(g_client_data.primitiva, "GDP_DISCOVERY", 13)){
      // [2] send GDP_OFFER
      sendto(sock, (char*)&g_server_data, sizeof(g_server_data), 0, (SOCKADDR*)&ip_client, g_ip_size);
      printf("sent server data\n");
    }
    else if (!strncmp(g_client_data.primitiva, "GDP_CONNECT", 11)){
      if (!strcmp(g_client_data.game, g_server_data.game)){ //??? sizeof
        // [3] send GDP_ACK
        memset(g_server_data.primitiva, 0, 25);
        strncpy(g_server_data.primitiva, "GDP_ACK\0", 8);
        sendto(sock, (char*)&g_server_data.primitiva, sizeof(g_server_data.primitiva), 0, (SOCKADDR*)&ip_client, g_ip_size);
        printf("client connected\n");
      }
      else {
        memset(g_server_data.primitiva, 0, 25);
        strncpy(g_server_data.primitiva, "GDP_ERROR\0", 8);
        sendto(sock, (char*)&g_server_data.primitiva, sizeof(g_server_data.primitiva), 0, (SOCKADDR*)&ip_client, g_ip_size);
        printf("ERROR, failed client request\n");
      }
    }
    else {
      memset(g_server_data.primitiva, 0, 25);
      strncpy(g_server_data.primitiva, "GDP_ERROR\0", 8);
      sendto(sock, (char*)&g_server_data.primitiva, sizeof(g_server_data.primitiva), 0, (SOCKADDR*)&ip_client, g_ip_size);
      printf("ERROR, failed client request\n");
    }
  }
}

// close sockets & WSA
void CloseWSA(){

  closesocket(sock);
  WSACleanup();
}

// main
int main(int argc, char** argv){

  InitWSA();
  Engine();
  CloseWSA();

  return 0;
}
